
/*
 * A V4L2 driver for Irs2975c Raw cameras.
 *
 * Copyright (c) 2017 by Allwinnertech Co., Ltd.  http://www.allwinnertech.com
 *
 * Authors:  Zhao Wei <zhaowei@allwinnertech.com>
 *	Yang Feng <yangfeng@allwinnertech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include "camera.h"
#include "sensor_helper.h"
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
#include "../../utility/vin_log.h"
#include "irs2975c_flash.h"

#define NEBULA_VERSION "1.5.3"

MODULE_AUTHOR("ww");
MODULE_DESCRIPTION("A low-level driver for Irs2975c Raw sensors");
MODULE_LICENSE("GPL");
MODULE_VERSION(NEBULA_VERSION);

#define IIC_DEV_NUM 3 // /dev/i2c-x
#define VIDEO_DEV_NUM 8 // /dev/videoX
#define IS_MASTER 1 //0: slave mode; 1: master mode
#define SENSOR_NAME "irs2975c_mipi_2"

#define MCLK (24 * 1000 * 1000)
#define V4L2_IDENT_SENSOR 0x2975
/* mode15 pixel 240 * 3255*/
#define TOF_WIDTH (240)
#define TOF_HETGHT (361 * 3 + 181 * 12)

#define IRS2975C_FPS_MIN (5)
#define IRS2975C_FPS_MAX (30)
#define IRS2975C_REG_MB0_FRAMETIME_MIN (0x91E7)
#define IRS2975C_REG_MB0_FRAMETIME (0x9362)

/* better to modify like module_param! */
static uint8_t irs2975c_is_master =
	IS_MASTER; // 1--> master mode  0--> slave mode
static uint32_t irs2975c_fps = 10;

static struct v4l2_subdev *sd_g;
static unsigned char *calib_data = NULL;
/*
 * The Irs2975c i2c address
 */

//#define Irs2975c_WRITE_ADDR (0x7A)
//#define Irs2975c_READ_ADDR  (0x7B)
#define I2C_ADDR 0x7a

struct deptrum_dev_info {
	int i2c_dev_num; // 模组对应的iic控制器号
	int video_idx; // 模组对应的vedio节点号，如/dev/video8，此处就为8
	char dev_name[12];
	char version[16]; // 驱动版本号
};

struct deptrum_sn_info {
	char sn[32];
	int len;
};

struct deptrum_calib_data {
	int offset;
	int len;
	unsigned char calib_data[4 * 1024];
};

struct deptrum_calib_info {
	int calib_len;
	int crc32;
};

struct deptrum_exp_info {
	unsigned short exp[64];
	int exp_num;
};

#pragma pack(1)
struct deptrum_product_info {
  uint16_t vid;     //!< Vendor ID
  uint16_t pid;     //!< Product ID
  uint16_t hw_ver;  //!< Hardware version
};
#pragma pack()
#define DEPTRUM_DEV_INFO _IOR('d', 0, struct deptrum_dev_info)
#define DEPTRUM_RESET_SENSOR _IOW('d', 1, int)
#define DEPTRUM_SET_MODE _IOW('d', 2, int)
#define DEPTRUM_GET_DATA_TYPE _IOR('d', 3, int)
#define DEPTRUM_GET_SN _IOR('d', 4, struct deptrum_sn_info)
#define DEPTRUM_GET_CALIB _IOWR('d', 5, struct deptrum_calib_data)
#define DEPTRUM_START_READ_CALIB _IOR('d', 6, struct deptrum_calib_info)
#define DEPTRUM_SET_EXP _IOW('d', 7, struct deptrum_exp_info)
#define DEPTRUM_GET_PRODUCT_INFO _IOR('d', 8, struct deptrum_product_info)

struct cfg_array { /* coming later */
	struct regval_list *regs;
	int size;
};

struct _REGS_VAL {
	unsigned short addr;
	unsigned short reg_val; // 寄存器值
	unsigned int exp_val; // us
	unsigned int f_illu; // khz
};

static struct _REGS_VAL expregs_mode15[] = {
	{ 0x9000, 0x4EB5, 128, 60240 },  { 0x9004, 0x4EB5, 2000, 60240 },
	{ 0x9008, 0x4EB5, 2000, 60240 }, { 0x900c, 0x4EB5, 2000, 60240 },
	{ 0x9010, 0x4EB5, 2000, 60240 }, { 0x9014, 0x4D3C, 2000, 60240 },
	{ 0x9018, 0x4D3C, 2000, 60240 },  { 0x901c, 0x4D3C, 2000, 60240 },
	{ 0x9020, 0x4D3C, 2000, 60240 },  { 0x9024, 0x4D3C, 10, 60240 },
	{ 0x9028, 0x2d2e, 10, 60240 },	  { 0x902c, 0x2d2e, 10, 50200 },
	{ 0x9030, 0x2d2e, 10, 50200 },	  { 0x9034, 0x2d2e, 10, 50200 },
	{ 0x9038, 0x2d2e, 10, 50200 },
};

/*
 * The default register settings
 *
 */
// mode15, goff(black),goff(led),gon,stof hfreq(100.4M,s3-s6),mtof hfreq(60.24M s7-s10), mtof
// lowfreq(50.2M s11-s14)
static struct regval_list sensor_default_regs[] = {
      {0xa000, 0x0018},
      {0xa001, 0x0000},
      {0xa004, 0x0c00},
      {0xa006, 0x0000},
      {0xA009, 0x1315},
      {0xA00A, 0x1513},
      {0xA00B, 0x1313},
      // mipi config is related to fref
      {0xA02F, 0x1EA1},  // PLL_SYSLUT_CFG0 (for fref = 24.00 MHz)
      {0xA030, 0xAAAB},  // PLL_SYSLUT_CFG1 (for fref = 24.00 MHz)
      {0xA031, 0x000A},  // PLL_SYSLUT_CFG2 (for fref = 24.00 MHz)
      {0xA032, 0x0000},  // PLL_SYSLUT_CFG3 (for fref = 24.00 MHz)
      {0xA033, 0x0280},  // PLL_SYSLUT_CFG4 (for fref = 24.00 MHz)
      {0xA034, 0x0000},  // PLL_SYSLUT_CFG5 (for fref = 24.00 MHz)
      {0xA035, 0x001F},  // PLL_SYSLUT_CFG6 (for fref = 24.00 MHz)
      {0xA03E, 0x0001},  // DPHYCLKCFG1 (MIPI timings for 560Mbps/lane)
      {0xA03F, 0x0009},  // DPHYCLKCFG_1GB (MIPI timings for 560Mbps/lane)
      {0xA041, 0x81C4},  // DPHYCLANECFG1 (MIPI timings for 560Mbps/lane)
      {0xA042, 0x0013},  // DPHYCLANECFG2 (MIPI timings for 560Mbps/lane)
      {0xA043, 0x0206},  // DPHYCLANECFG3 (MIPI timings for 560Mbps/lane)
      {0xA044, 0x000E},  // DPHYCLANECFG_1GB (MIPI timings for 560Mbps/lane)
      {0xA046, 0x0302},  // DPHYDLANECFG_1GB_1 (MIPI timings for 560Mbps/lane)
      {0xA047, 0x0305},  // DPHYDLANECFG_1GB_2 (MIPI timings for 560Mbps/lane)
      {0xA048, 0x0002},  // DPHYDLANECFG_1GB_3 (MIPI timings for 560Mbps/lane)
      {0xA04C, 0x0404},  // DPHYDLANECFG4 (MIPI timings for 560Mbps/lane)

      {0x9000, 0x1E1E},  // s0 128us
      {0x9002, 0x00A0},
      {0x9003, 0x8300},
      {0x9004, 0x1E1E},
      {0x9006, 0x00A0},
      {0x9007, 0x8300},
      {0x9008, 0x1E1E},
      {0x900A, 0x00A0},
      {0x900B, 0x8300},
      {0x900C, 0x1E1E},  // s3
      {0x900E, 0x0000},
      {0x900F, 0x0000},
      {0x9010, 0x1E1E},
      {0x9012, 0x0000},
      {0x9013, 0x0002},
      {0x9014, 0x1E1E},
      {0x9016, 0x0000},
      {0x9017, 0x0004},
      {0x9018, 0x1E1E},
      {0x901A, 0x0000},
      {0x901B, 0x0006},
      {0x901C, 0x1E1E},  // s7
      {0x901E, 0x0002},
      {0x901F, 0x0000},
      {0x9020, 0x1E1E},
      {0x9022, 0x0002},
      {0x9023, 0x0002},
      {0x9024, 0x1E1E},
      {0x9026, 0x0002},
      {0x9027, 0x0004},
      {0x9028, 0x1E1E}, //s10
      {0x902A, 0x0002},
      {0x902B, 0x0006},
      {0x902C, 0x1919},  // s11  128us
      {0x902E, 0x0004},
      {0x902F, 0x0000},
      {0x9030, 0x1919},
      {0x9032, 0x0004},
      {0x9033, 0x0002},
      {0x9034, 0x1919},
      {0x9036, 0x0004},
      {0x9037, 0x0004},
      {0x9038, 0x1919},
      {0x903A, 0x0004},
      {0x903B, 0xC006},
      {0x9100, 0x9262},  // s0 max exp 2500us，60.24MHz
      {0x9102, 0x00A0},  // goff
      {0x9103, 0x9262},
      {0x9105, 0x00A1},  // led gpio output,goff
      {0x9106, 0x9262},
      {0x9108, 0x0000},  // gon
      {0x9109, 0x9262},
      {0x910B, 0x0000},
      {0x910C, 0x9262},
      {0x910E, 0x0000},
      {0x910F, 0x9262},
      {0x9111, 0x0000},
      {0x9112, 0x9262},
      {0x9114, 0x0000},
      {0x9115, 0x9262},
      {0x9117, 0x1002},
      {0x9118, 0x9262},
      {0x911A, 0x1002},
      {0x911B, 0x9262},
      {0x911D, 0x1002},
      {0x911E, 0x9262},
      {0x9120, 0x1002},
      {0x9121, 0x7D47},  // s11
      {0x9123, 0x2004},
      {0x9124, 0x7D47},
      {0x9126, 0x2004},
      {0x9127, 0x7D47},
      {0x9129, 0x2004},
      {0x912A, 0x7D47},
      {0x912C, 0x2004},
      {0x91C0, 0x0112},
      {0x91C1, 0x2140},
      {0x91C3, 0x0042},
      {0x91C4, 0x0000},
      {0x91CB, 0x012D},
      {0x91CC, 0x0020},
      {0x91CD, 0x0810},
      {0x91D6, 0x0035},
      {0x91DF, 0x010F},
      {0x91E7, 0x124F},
      {0x91EF, 0x0008},
      {0x9206, 0x16A1},
      {0x9207, 0x1EB8},
      {0x9208, 0x0005},
      {0x9209, 0x3F01},
      {0x920A, 0xAAA0}, // ssc on
      {0x920B, 0x04A2},
      {0x920C, 0x005B},
      {0x920D, 0x0029},
      {0x920E, 0x16A1},
      {0x920F, 0x1EB8},
      {0x9210, 0x0005},
      {0x9211, 0x3F01},
      {0x9212, 0xAAA0},  // ssc on
      {0x9213, 0x04A2},
      {0x9214, 0x005B},
      {0x9215, 0x0029},
      {0x9216, 0x1AA1},
      {0x9217, 0xEEEF},
      {0x9218, 0x000E},
      {0x9219, 0x1101},
      {0x921A, 0xAAA0},  // ssc on
      {0x921B, 0x03C2},
      {0x921C, 0x005B},
      {0x921D, 0x0031},
      {0x923C, 0x0007},
      {0x923D, 0x00F0},
      {0x9245, 0x0007},
      {0x9246, 0x00F0},
      {0x924E, 0x0007},
      {0x924F, 0x00F0},
      {0x9260, 0x0007},
      {0x9261, 0x00E0},
      {0x9269, 0x0007},
      {0x926A, 0x00E0},
      {0x9272, 0x0007},
      {0x9273, 0x00E0},
      {0x9284, 0x0E00},
      {0x9289, 0x0E00},
      {0x928E, 0x0E00},
      {0x9294, 0x0600},
      {0x9299, 0x0600},
      {0x929E, 0x0600},
      {0x935C, 0x0000},
      {0x935D, 0x00B3},
      {0x935E, 0x0000},
      {0x935F, 0x00EF},
      {0x9360, 0x0000},
      {0x9362, 0x124F},
      {0x9401, 0x0002},
};

/*
 * Here we'll try to encapsulate the changes for just the output
 * video format.
 *
 */

static struct regval_list sensor_fmt_raw[] = {};

static int sensor_g_exp(struct v4l2_subdev *sd, __s32 *value)
{
	struct sensor_info *info = to_state(sd);

	*value = info->exp;
	sensor_dbg("sensor_get_exposure = %d\n", info->exp);
	return 0;
}

static int sensor_s_exp(struct v4l2_subdev *sd, unsigned int exp_val)
{
	return 0;
}

static int sensor_g_gain(struct v4l2_subdev *sd, __s32 *value)
{
	struct sensor_info *info = to_state(sd);

	*value = info->gain;
	sensor_dbg("sensor_get_gain = %d\n", info->gain);
	return 0;
}

unsigned int BASEGAIN = 128;

static int sensor_s_gain(struct v4l2_subdev *sd, int gain_val)
{
	return 0;
}

static int sensor_s_exp_gain(struct v4l2_subdev *sd,
			     struct sensor_exp_gain *exp_gain)
{
	return 0;
}

static int sensor_s_sw_stby(struct v4l2_subdev *sd, int on_off)
{
	int ret = 0;
	return ret;
}

/*
 * Stuff that knows about the sensor.
 */

static int sensor_power(struct v4l2_subdev *sd, int on)
{
	int ret;

	ret = 0;
	switch (on) {
	case STBY_ON:
		sensor_dbg("STBY_ON!\n");
		ret = sensor_s_sw_stby(sd, CSI_GPIO_HIGH);
		if (ret < 0)
			sensor_err("soft stby falied!\n");
		usleep_range(10000, 12000);
		cci_lock(sd);
		vin_gpio_write(sd, PWDN, CSI_GPIO_HIGH);
		cci_unlock(sd);
		vin_set_mclk(sd, OFF);
		break;
	case STBY_OFF:
		sensor_dbg("STBY_OFF!\n");
		cci_lock(sd);
		vin_set_mclk_freq(sd, MCLK);
		vin_set_mclk(sd, ON);
		usleep_range(10000, 12000);
		vin_gpio_write(sd, PWDN, CSI_GPIO_LOW);
		usleep_range(10000, 12000);
		ret = sensor_s_sw_stby(sd, CSI_GPIO_LOW);
		if (ret < 0)
			sensor_err("soft stby off falied!\n");
		cci_unlock(sd);
		break;
	case PWR_ON:
		sensor_print("PWR_ON!\n");
		cci_lock(sd);
		// vin_set_pmu_channel(sd, CAMERAVDD, ON);
		//vin_gpio_write(sd, PWDN, CSI_GPIO_LOW);
		//vin_gpio_write(sd, POWER_EN, CSI_GPIO_HIGH);
		vin_gpio_set_status(sd, POWER_EN, 1);
		vin_gpio_write(sd, POWER_EN, CSI_GPIO_HIGH);
		usleep_range(7000, 8000);
		vin_set_pmu_channel(sd, IOVDD, ON);
		usleep_range(7000, 8000);
		vin_set_pmu_channel(sd, AVDD, ON);
		usleep_range(7000, 8000);
		// vin_set_pmu_channel(sd, DVDD, ON);
		//usleep_range(7000, 8000);
		vin_set_mclk_freq(sd, MCLK);
		vin_set_mclk(sd, ON);
		usleep_range(10000, 12000);
		//vin_gpio_write(sd, PWDN, CSI_GPIO_HIGH);
		//usleep_range(10000, 12000);
		ret = vin_gpio_write(sd, RESET, CSI_GPIO_HIGH);
		if (ret)
			sensor_err("reset error\n");
		cci_unlock(sd);
		break;
	case PWR_OFF:
		sensor_print("PWR_OFF!\n");
		cci_lock(sd);
		// vin_gpio_write(sd, PWDN, CSI_GPIO_HIGH);
		vin_set_mclk(sd, OFF);
		usleep_range(7000, 8000);
		//vin_gpio_write(sd, PWDN, CSI_GPIO_LOW);
		//vin_gpio_write(sd, POWER_EN, CSI_GPIO_LOW);
		vin_gpio_write(sd, RESET, CSI_GPIO_LOW);
		vin_set_pmu_channel(sd, AVDD, OFF);
		vin_set_pmu_channel(sd, IOVDD, OFF);
		cci_unlock(sd);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int sensor_reset(struct v4l2_subdev *sd, u32 val)
{
	sensor_print("sensor_reset!val=%d\n", val);
	switch (val) {
	case 0:
		vin_gpio_write(sd, RESET, CSI_GPIO_HIGH);
		usleep_range(10000, 12000);
		break;
	case 1:
		vin_gpio_write(sd, RESET, CSI_GPIO_LOW);
		usleep_range(10000, 12000);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int sensor_reset_(void)
{
	int ret;
	if (!sd_g) {
		sensor_err("sensor_reset error,sd is null\n");
		return -1;
	}

	ret = vin_gpio_set_status(sd_g, RESET, 1);
	ret = vin_gpio_write(sd_g, RESET, CSI_GPIO_LOW);
	usleep_range(10000, 12000);
	ret = vin_gpio_write(sd_g, RESET, CSI_GPIO_HIGH);
	return 0;
}

static int sensor_detect(struct v4l2_subdev *sd)
{
	data_type rdval;

	sensor_read(sd, 0xA0A4, &rdval);
	if (rdval != 0x2975) {
		sensor_err("not found front sensor\n");
		return -1;
	} else
		sensor_print("0XA0A4 =  0x%x\n", rdval);
	return 0;
}
struct fps_regval {
	unsigned int fps;
	unsigned short val;
};
#if 0
static const struct fps_regval irs2975c_fps_global_reg[] = { { 5, 0x124f }, { 6, 0xf42 }, { 7, 0xd14 }, { 8, 0xb71 }, { 9, 0xa2c }, { 10, 0x927 }, { 11, 0x852 } };

static const struct fps_regval irs2975c_slave_fps_global_reg[] = { { 5, 0x1165 }, { 6, 0xe7e }, { 7, 0xc6c }, { 8, 0xade }, { 9, 0x9a8 }, { 10, 0x8b0 } };
#endif
static const struct fps_regval irs2975c_fps_global_reg_mb0[] = {
	{ 10, 0x124F }, { 11, 0x10A4 }, { 12, 0x0F41 }, { 13, 0x0E15 },
	{ 14, 0x0D13 }, { 15, 0x0C34 }, { 16, 0x0B71 }, { 17, 0x0AC4 },
	{ 18, 0x0A2B }, { 19, 0x09A2 }, { 20, 0x0927 }, { 21, 0x08B7 },
	{ 22, 0x0852 }, { 23, 0x07F5 }, { 24, 0x07A0 }, { 25, 0x0752 },
	{ 26, 0x070A }, { 27, 0x06C7 }, { 28, 0x0689 }, { 29, 0x064F },
	{ 30, 0x061A }
};

#if 0
static struct regval_list irs2975c_slave_mode[] = { 
	{ 0xA00B, 0x131A }, // PADGPIOCFG2-->gpio4
	{ 0x8611, 0x0020 }, // IRQ ack
	{ 0x9401, 0x8002 },
	{ 0x9402, 0x0000 },
	{ 0xA001, 0X00A0 }
};
#else
static struct regval_list irs2975c_slave_mode[] = {
	{ 0xA00B, 0x131A }, // PADGPIOCFG2-->gpio4
	{ 0x8611, 0x0020 }, // IRQ ack
	{ 0x9401, 0x8002 },
	{ 0x9402, 0x0001 },
	{ 0xA001, 0X00A0 }  //DMUX1 --> connect pad of GPIO4 to trigger-in signal via DMUX
};
#endif
static struct regval_list irs2975c_master_mode[] = {
	{ 0xA00B, 0x1315 }, //#PADGPIOCFG2(GPIO5=High-z, GPIO4=Output)
	{ 0x8611, 0xFFFF }, { 0x9401, 0X0002 }, { 0x9402, 0x0000 },
	{ 0xA001, 0X0000 }, { 0x9400, 0x0000 }
};

static int8_t irs2975c_set_fps(struct v4l2_subdev *sd, unsigned int fps)
{
	unsigned short reg_val = 0;
	int8_t ret = -1;
	int i;

	if (fps < IRS2975C_FPS_MIN || fps > IRS2975C_FPS_MAX) {
		sensor_err("=== irs2975c set fps(%u) error!=====\n", fps);
		goto RETURN_RET;
	}

	if (1 == irs2975c_is_master) {
		for (i = 0; i < (sizeof(irs2975c_fps_global_reg_mb0) /
				 sizeof(irs2975c_fps_global_reg_mb0[0]));
		     i++) {
			if (fps == irs2975c_fps_global_reg_mb0[i].fps) {
				reg_val = irs2975c_fps_global_reg_mb0[i].val;
				break;
			}
		}

		if (reg_val != 0) {
			ret = sensor_write(sd, IRS2975C_REG_MB0_FRAMETIME_MIN,
					   0x249e);
			ret |= sensor_write(sd, IRS2975C_REG_MB0_FRAMETIME,
					    reg_val);
			if (ret) {
				sensor_print(
					"master mode === irs2975c_write_register set fps error!=====\n");
				goto RETURN_RET;

			} else {
				sensor_print(
					"master mode === irs2975c_write_register set master mode fps(%u) success!=====\n",
					fps);
			}
		}
	} else if (0 ==
		   irs2975c_is_master) /* slave mode: FPS ≳ trig HZ ensure to sync the exposure signal with the trig HZ */
	{
		fps += 2;

		for (i = 0; i < (sizeof(irs2975c_fps_global_reg_mb0) /
				 sizeof(irs2975c_fps_global_reg_mb0[0]));
		     i++) {
			if (fps == irs2975c_fps_global_reg_mb0[i].fps) {
				reg_val = irs2975c_fps_global_reg_mb0[i].val;
				break;
			}
		}

		/* trig 10hz fps 12 fixed! custom modified! */
		ret = sensor_write(sd, IRS2975C_REG_MB0_FRAMETIME_MIN, 0x249e);
		ret |= sensor_write(sd, IRS2975C_REG_MB0_FRAMETIME, reg_val);
		if (ret) {
			sensor_print(
				"slave mode === irs2975c_write_register set fps error!===\n");
			goto RETURN_RET;

		} else {
			sensor_print(
				"slave mode === irs2975c_write_register set slave mode fps(%d) success!===\n",
				fps);
		}
	}

RETURN_RET:
	return ret;
}

int8_t irs2975c_setting_master_mode(struct v4l2_subdev *sd)
{
	uint8_t i;
	int8_t ret;

	/*step1: writing master regs to sensor*/
	for (i = 0;
	     i < sizeof(irs2975c_master_mode) / sizeof(struct regval_list);
	     i++) {
		ret = sensor_write(sd, irs2975c_master_mode[i].addr,
				   irs2975c_master_mode[i].data);
		if (ret) {
			return ret;
		}
	}
	return 0;
}

int8_t irs2975c_setting_slave_mode(struct v4l2_subdev *sd)
{
	uint8_t i;
	int8_t ret;
	/*step1: writing slave regs to sensor*/
	for (i = 0;
	     i < sizeof(irs2975c_slave_mode) / sizeof(struct regval_list);
	     i++) {
		ret = sensor_write(sd, irs2975c_slave_mode[i].addr,
				   irs2975c_slave_mode[i].data);
		if (ret) {
			return ret;
		}
	}

	return 0;
}

static int sensor_init(struct v4l2_subdev *sd, u32 val)
{
	int ret;
	struct sensor_info *info = to_state(sd);

	sensor_print("sensor_init\n");

	vin_gpio_set_status(sd, RESET, 1);
	vin_gpio_write(sd, RESET, CSI_GPIO_LOW);
	usleep_range(10000, 12000);
	vin_gpio_write(sd, RESET, CSI_GPIO_HIGH);
	usleep_range(10000, 12000);

	/* Make sure it is a target sensor */
	ret = sensor_detect(sd);
	if (ret) {
		sensor_err("chip found is not an target chip.\n");
		return ret;
	}

	info->focus_status = 0;
	info->low_speed = 0;
	info->width = TOF_WIDTH;
	info->height = TOF_HETGHT;
	info->hflip = 0;
	info->vflip = 0;
	info->gain = 0;

	info->tpf.numerator = 1;
	info->tpf.denominator = irs2975c_fps;

	
	sensor_print("2975c init ok.\n");
	info->preview_first_flag = 1;

	return 0;
}

// param exp: us
// param f_illu: KHz
int calc_exp_reg(int exp, int f_illu)
{
	int t_expo_reg_max = 16383;
	int prescaler = 0;
	int prescaler_ID = 0;
	int reg;
	// printk("calc_exp_reg exp=%d, fillu=%d\n", exp, f_illu);
	// printk("calc_exp_reg case1=%d\n", (t_expo_reg_max * 1 * 1000 / f_illu));

	if ((t_expo_reg_max * 1 * 1000 / f_illu) > exp) {
		prescaler = 1;
		prescaler_ID = 0;
	} else if (t_expo_reg_max * 8 * 1000 / f_illu > exp) {
		prescaler = 8;
		prescaler_ID = 1;
	} else if (t_expo_reg_max * 32 * 1000 / f_illu > exp) {
		prescaler = 32;
		prescaler_ID = 2;
	} else if (t_expo_reg_max * 128 * 1000 / f_illu > exp) {
		prescaler = 128;
		prescaler_ID = 3;
	} else {
		return -1;
	}
	reg = prescaler_ID * 0x4000 + f_illu * exp / (1000 * prescaler);
	return reg;
}

int get_exp(int type, uint16_t exp[])
{
	int i;
	struct _REGS_VAL *temp = expregs_mode15;

	for (i = 0; i < 15; i++) {
		exp[i] = (uint16_t)temp[i].exp_val;
		// printk("%d, exp_val = %d,reg=%x\n", i, exp[i], ret);
	}
	return 0;
}

int set_exp(struct v4l2_subdev *sd, uint16_t exp[], int size)
{
	int i;
	int ret;
	struct _REGS_VAL *temp = expregs_mode15;

	for (i = 0; i < size; i++) {
		if (exp[i] > 3000) {
			sensor_err("exp value is invalid\n");
			return -1;
		}
		ret = calc_exp_reg(exp[i], temp[i].f_illu);
		if (ret < 0) {
			sensor_err("calc_exp_reg is error.\n");
			return -2;
		}

		temp[i].exp_val = exp[i];
		temp[i].reg_val = ret;
		//sensor_err("=== set exp addr=%x, val=%x\n", temp[i].addr, temp[i].reg_val);
		ret = sensor_write(sd, temp[i].addr, temp[i].reg_val);
		if (ret) {
			sensor_err("=== set exp %d error\n", i);
			return -3;
		}
	}

	ret = sensor_write(sd, 0x9403, 0x0001);
	if (ret) {
		sensor_err("=== set exp chang error\n");
		return -4;
	}
	return 0;
}

static long sensor_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
	int ret = 0;
	struct sensor_info *info = to_state(sd);
	struct deptrum_dev_info dev_info;

	//sensor_print("cmd magic=%c\n", _IOC_TYPE(cmd));
	//sensor_print("[%s] command numer [%d] exceeded!\n", __func__, _IOC_NR(cmd));

	switch (cmd) {
	case GET_CURRENT_WIN_CFG:
		if (info->current_wins != NULL) {
			memcpy(arg, info->current_wins,
			       sizeof(*info->current_wins));
			ret = 0;
		} else {
			sensor_err("empty wins!\n");
			ret = -1;
		}
		break;
	case SET_FPS:
		break;
	case VIDIOC_VIN_SENSOR_EXP_GAIN:
		ret = sensor_s_exp_gain(sd, (struct sensor_exp_gain *)arg);
		break;
	case VIDIOC_VIN_SENSOR_CFG_REQ:
		sensor_cfg_req(sd, (struct sensor_config *)arg);
		break;
	case VIDIOC_VIN_FLASH_EN:
		ret = flash_en(sd, (struct flash_para *)arg);
		break;
	case DEPTRUM_DEV_INFO:
		memset(&dev_info, 0, sizeof(dev_info));
		strcpy(dev_info.dev_name, "nebula280");
		dev_info.i2c_dev_num = IIC_DEV_NUM;
		dev_info.video_idx = VIDEO_DEV_NUM;
		strncpy(dev_info.version, NEBULA_VERSION,
			strlen(NEBULA_VERSION));
		memcpy(arg, &dev_info, sizeof(dev_info));
		sensor_print("DEPTRUM_DEV_INFO get,version=%s!\n",
			     dev_info.version);
		break;
	case DEPTRUM_RESET_SENSOR:
		ret = sensor_reset_();
		sensor_print("reset sensor.ret= %d\n", ret);
		break;
	case DEPTRUM_SET_MODE: {
		int mode = *(int *)arg;
		if (mode == 0) {
			irs2975c_is_master = 0;
			sensor_print("set slave mode\n");
		} else {
			irs2975c_is_master = 1;
			sensor_print("set master mode\n");
		}
	} break;
	case DEPTRUM_GET_SN: {
		struct deptrum_sn_info sn_info;
		int ret;
		memset(&sn_info, 0, sizeof(sn_info));
		sensor_reset_();
		//write_sn(sd, "TS400467002014605100134", 23);
		ret = read_sn(sd, sn_info.sn);
		if (ret) {
			return ret;
		}
		memcpy(arg, &sn_info, sizeof(sn_info));
		sensor_print("DEPTRUM_GET_SN get sn=%s!\n", sn_info.sn);
	} break;
	case DEPTRUM_GET_CALIB: {
		struct deptrum_calib_data *calib_info =
			(struct deptrum_calib_data *)arg;
		if (calib_info->len > sizeof(calib_info->calib_data))
			return -EINVAL;
		memcpy(calib_info->calib_data, calib_data + calib_info->offset, calib_info->len);
		//sensor_print("DEPTRUM_GET_CALIB!idx=%d\n", calib_info->idx);
	} break;
	case DEPTRUM_START_READ_CALIB: {
		struct deptrum_calib_info calib_info;
		sensor_reset_();
		read_calib_info(sd, calib_data, &calib_info.calib_len,
				&calib_info.crc32);
		memcpy(arg, &calib_info, sizeof(calib_info));
		sensor_print("DEPTRUM_START_READ_CALIB!\n");
	} break;
	case DEPTRUM_SET_EXP: {
		int ret;
		struct deptrum_exp_info *exp_info =
			(struct deptrum_exp_info *)arg;
		ret = set_exp(sd, exp_info->exp, exp_info->exp_num);
		if (ret)
			sensor_err("DEPTRUM_SET_EXP err ret=%d!\n", ret);
		sensor_print("DEPTRUM_SET_EXP!\n");
	} break;
	case DEPTRUM_GET_PRODUCT_INFO: {
		struct deptrum_product_info product_info;
		int ret;
		memset(&product_info, 0, sizeof(product_info));
		sensor_reset_();
		ret = read_device_info(sd, (uint8_t *)&product_info);
		if (ret) {
			return ret;
		}
		memcpy(arg, &product_info, sizeof(product_info));
		sensor_print("get product info pid=0x%x, hw_ver=0x%x!\n", product_info.pid, product_info.hw_ver);
	} break;
	default:
		return -EINVAL;
	}
	return ret;
}

/*
 * Store information about the video data format.
 */
static struct sensor_format_struct sensor_formats[] = {
	{ .desc = "Raw RGB Bayer",
	  .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
	  .regs = sensor_fmt_raw,
	  .regs_size = ARRAY_SIZE(sensor_fmt_raw),
	  .bpp = 1 },
};
#define N_FMTS ARRAY_SIZE(sensor_formats)

/*
 * Then there is the issue of window sizes.  Try to capture the info here.
 */
static struct sensor_win_size sensor_win_sizes[] = {
	{
		.width = TOF_WIDTH,
		.height = TOF_HETGHT,
		.hoffset = 0,
		.voffset = 0,
		.hts = 1000,
		.vts = 4000,
		.pclk = 80 * 1000 * 1000,
		.mipi_bps = 480 * 1000 * 1000,
		.fps_fixed = 20,
		.bin_factor = 1,
		.intg_min = 4 << 4,
		.intg_max = (TOF_HETGHT) << 4,
		.gain_min = 1 << 4,
		.gain_max = 32 << 4,
		.regs = sensor_default_regs,
		.regs_size = ARRAY_SIZE(sensor_default_regs),
		.set_size = NULL,
	},
};

#define N_WIN_SIZES (ARRAY_SIZE(sensor_win_sizes))


static unsigned short ram_firmware_mem_page_0[] = {
    38625, 20059, 15429, 63653, 29701, 59548, 35068, 30720, 30720, 2577,  256,   28384, 65259,
    30720, 30720, 63488, 28384, 65088, 28384, 65088, 50144, 28384, 3650,  63488, 63488, 30720,
    30720, 63488, 30720, 63488, 63488, 30720, 28384, 56941, 61152, 24173, 63488, 28384, 11887,
    63488, 63488, 30720, 30720, 63488, 30720, 63488, 63488, 30720, 20121, 20121, 30720, 61152,
    30720, 61152, 48795, 30720, 30720, 63488, 63488, 30720, 63488, 30720, 30720, 63488, 28384,
    34324, 62469, 26780, 62469, 8605,  29701, 45726, 62469, 31647, 29701, 62624, 29701, 48545,
    62469, 11938, 62469, 26531, 21424, 62469, 164,   38625, 38736, 15429, 164,   56192, 48197,
    26780, 48197, 8605,  15429, 45726, 48197, 31647, 15429, 62624, 15429, 48545, 48197, 11938,
    15429, 59299, 52039, 5812,  46592, 28384, 3620,  62469, 26780, 62469, 41373, 29701, 45726,
    29701, 31647, 62469, 62624, 29701, 15777, 62469, 11938, 62469, 59299, 21424, 29701, 32932,
    61152, 30466, 48197, 164,   23424, 48197, 59548, 15429, 8605,  48197, 12958, 48197, 64415,
    15429, 62624, 15429, 15777, 48197, 11938, 48197, 59299, 13994, 26159, 61152, 54836, 29701,
    59548, 29701, 8605,  62469, 45726, 29701, 31647, 62469, 29856, 62469, 48545, 29701, 11938,
    62469, 59299, 21424, 62469, 164,   28384, 61195, 15429, 32932, 56192, 15429, 59548, 15429,
    8605,  48197, 45726, 15429, 31647, 48197, 29856, 48197, 48545, 15429, 44706, 15429, 26531,
    35665, 16021, 40564, 35682, 4971,  24772, 49988, 47941, 32512, 57632, 17272, 20984, 52039,
    9072,  35304, 45894, 7016,  35304, 15173, 31584, 35304, 49988, 31584, 16882, 34345, 7016,
    47603, 34342, 15173, 31584, 39394, 49988, 16833, 65281, 20665, 28384, 40141, 50040, 23409,
    2300,  50244, 16151, 48832, 44938, 20992, 58369, 26183, 13382, 49194, 11007, 60608, 64518,
    16426, 19718, 46150, 49194, 20992, 34879, 31750, 16426, 57540, 3076,  36944, 35068, 11132,
    54141, 16833, 19720, 45507, 40713, 31736, 16833, 38666, 12739, 65281, 39920, 4952,  43510,
    21477, 31735, 39394, 13126, 43855, 38625, 18243, 15173, 62469, 49574, 7015,  49601, 28420,
    12739, 35845, 49601, 1030,  31736, 45507, 25601, 39920, 37720, 10742, 9191,  62452, 39394,
    13126, 43855, 5857,  18243, 41804, 27498, 43510, 56141, 15429, 60326, 31584, 25059, 49988,
    49563, 4952,  31571, 49514, 4562,  45894, 49563, 29535, 61152, 28614, 2300,  45946, 23409,
    47990, 44551, 24772, 10742, 49995, 54130, 29158, 37720, 2300,  17272, 35068, 15429, 61340,
    38625, 3843,  45894, 29701, 30885, 65280, 55262, 9926,  3697,  65280, 10378, 50244, 59664,
    27585, 12739, 51457, 35844, 22544, 65331, 30975, 31750, 57403, 65280, 26628, 31750, 49219,
    16170, 49194, 64518, 60,    65280, 24584, 31750, 41028, 14101, 51315, 64518, 30781, 32512,
    34828, 64518, 22597, 46150, 0,     20992, 63489, 64518, 0,     13382, 32768, 20992, 61442,
    64518, 0,     13382, 32768, 53760, 26628, 64518, 0,     17476, 55312, 10424, 35844, 55312,
    24772, 64518, 4195,  32512, 57352, 64518, 30721, 30720, 35068, 30720, 63488, 63488, 30720};

static struct regval_list ism_settings[] = {
    {34304, 7},
    {34363, 13311},
    {34371, 4},
    {34364, 10794},
    {34372, 8},
    {34365, 5491},
    {34373, 12},
};

int update_fw(struct v4l2_subdev *sd) {
	int ret = 0;
	int base_addr = 0x8800;
	int i;
	for (i = 0; i < sizeof(ram_firmware_mem_page_0) / sizeof(ram_firmware_mem_page_0[0]); i++) {
		ret = sensor_write(sd, base_addr++, ram_firmware_mem_page_0[i]);
		if (ret) {
			sensor_print("=== write ram_firmware_mem_page_0 error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!=====\n");
			return -1;
		}
	}

	for (i = 0; i < sizeof(ism_settings) / sizeof(ism_settings[0]); i++) {
		ret = sensor_write(sd, ism_settings[i].addr, ism_settings[i].data);
		if (ret) {
			sensor_print("=== write ism_settings error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!=====\n");
			return -1;
		}
	}
	sensor_print("===  update_fw ok!!!!!!!!!!!!!!!!!!!!!!!!!!!!!=====\n");
	return 0;
}

#define ENABLE_REG (0x01)
#define IVFM_REG (0x02)
#define LED1_FLASH_BRIGHTNESS_REG (0x03)
#define LED2_FLASH_BRIGHTNESS_REG (0x04)
#define LED1_TORCH_BRIGHTNESS_REG (0x05)
#define LED2_TORCH_BRIGHTNESS_REG (0x06)
#define BOOST_CONF_REG (0x07)
#define TIMING_CONF_REG (0x08)
#define TEMP_REG (0x09)
#define FLAGS1_REG (0x0A)
#define FLAGS2_REG (0x0B)
#define ID_REG (0x0C)

// 200mA*2
static struct regval_list led_dft_conf[] = {
    {ENABLE_REG, 0xA4},
    {IVFM_REG, 0x00},
    {LED1_FLASH_BRIGHTNESS_REG, 0x19},
    {LED2_FLASH_BRIGHTNESS_REG, 0x19},
    {BOOST_CONF_REG, 0x0F},
    {ENABLE_REG, 0xA7},
    {0xff, 0x00},
};

int led_driver_init(struct v4l2_subdev *sd) {
	int ret = 0;
	int i;
	//设置led driver的iic地址
	struct i2c_client *client = v4l2_get_subdevdata(sd);
	struct cci_driver *cci_drv = v4l2_get_subdev_hostdata(sd);
	client->addr = 0x63;
	cci_drv->addr_width = 8;
	cci_drv->data_width = 8;

	for (i = 0; i < sizeof(led_dft_conf) / sizeof(struct regval_list); i++) {
		int ret = sensor_write(sd, led_dft_conf[i].addr, led_dft_conf[i].data);
		if (ret) {
			sensor_print("=== led_driver_write_register error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!=====\n");
			goto error;
		}
	}
	sensor_print("=== led_driver init ok==========\n");
error://恢复为camera iic地址
	client->addr = I2C_ADDR >> 1;
	cci_drv->addr_width = 16;
	cci_drv->data_width = 16;
	return ret;
}

static int sensor_s_stream(struct v4l2_subdev *sd, int enable)
{
	int ret;
	struct sensor_info *info = to_state(sd);

	sensor_print("%s on = %d, %d*%d %x\n", __func__, enable,
		     info->current_wins->width, info->current_wins->height,
		     info->fmt->mbus_code);
	if (enable) {
		update_fw(sd);
		ret = sensor_write_array(sd, sensor_default_regs,
					 ARRAY_SIZE(sensor_default_regs));
		if (ret < 0) {
			sensor_err("write sensor_default_regs error\n");
			return ret;
		}

		if (irs2975c_is_master == 0) { // 1--> master mode;0--> slave mode
			ret = irs2975c_setting_slave_mode(sd);
			if (ret)
				sensor_print("writing slave mode error!\n");
			else
				sensor_print("writing slave mode success!\n");
		} else if (irs2975c_is_master == 1) {
			ret = irs2975c_setting_master_mode(sd);
			if (ret)
				sensor_print("writing master mode error!\n");
			else
				sensor_print("writing master mode success!\n");
		}
		ret = irs2975c_set_fps(sd, irs2975c_fps);
		if (ret) {
			sensor_err("---irs2975c_set_fps err!\n");
			return ret;
		}
		led_driver_init(sd);
	}else {
		if (irs2975c_is_master == 0) {
			sensor_write(sd, 0x9402, (data_type)0x0007);
		}
	}
	sensor_write(sd, 0x9400, (data_type)enable);

	if (!enable)
		return 0;
	return 0;
}

static int sensor_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
				struct v4l2_mbus_config *cfg)
{
	cfg->type = V4L2_MBUS_CSI2_DPHY;
	cfg->flags = 0 | V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0;
	return 0;
}

static int sensor_g_ctrl(struct v4l2_ctrl *ctrl)
{
	struct sensor_info *info =
		container_of(ctrl->handler, struct sensor_info, handler);
	struct v4l2_subdev *sd = &info->sd;

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		return sensor_g_gain(sd, &ctrl->val);
	case V4L2_CID_EXPOSURE:
		return sensor_g_exp(sd, &ctrl->val);
	}
	return -EINVAL;
}

static int sensor_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct sensor_info *info =
		container_of(ctrl->handler, struct sensor_info, handler);
	struct v4l2_subdev *sd = &info->sd;

	switch (ctrl->id) {
	case V4L2_CID_GAIN:
		return sensor_s_gain(sd, ctrl->val);
	case V4L2_CID_EXPOSURE:
		return sensor_s_exp(sd, ctrl->val);
	}
	return -EINVAL;
}

/* ----------------------------------------------------------------------- */

static const struct v4l2_ctrl_ops sensor_ctrl_ops = {
	.g_volatile_ctrl = sensor_g_ctrl,
	.s_ctrl = sensor_s_ctrl,
};

static const struct v4l2_subdev_core_ops sensor_core_ops = {
	.reset = sensor_reset,
	.init = sensor_init,
	.s_power = sensor_power,
	.ioctl = sensor_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl32 = sensor_compat_ioctl32,
#endif
};

static const struct v4l2_subdev_video_ops sensor_video_ops = {
	.s_stream = sensor_s_stream,
};

static const struct v4l2_subdev_pad_ops sensor_pad_ops = {
	.enum_mbus_code = sensor_enum_mbus_code,
	.enum_frame_size = sensor_enum_frame_size,
	.get_fmt = sensor_get_fmt,
	.set_fmt = sensor_set_fmt,
	.get_mbus_config = sensor_g_mbus_config,
};

static const struct v4l2_subdev_ops sensor_ops = {
	.core = &sensor_core_ops,
	.video = &sensor_video_ops,
	.pad = &sensor_pad_ops,
};

/* ----------------------------------------------------------------------- */
static struct cci_driver cci_drv = {
	.name = SENSOR_NAME,
	.addr_width = CCI_BITS_16,
	.data_width = CCI_BITS_16,
};

static const struct v4l2_ctrl_config sensor_custom_ctrls[] = {
	{
		.ops = &sensor_ctrl_ops,
		.id = V4L2_CID_FRAME_RATE,
		.name = "frame rate",
		.type = V4L2_CTRL_TYPE_INTEGER,
		.min = 0,
		.max = 0,
		.step = 0,
		.def = 0,
	},
};

static int sensor_init_controls(struct v4l2_subdev *sd,
				const struct v4l2_ctrl_ops *ops)
{
	struct sensor_info *info = to_state(sd);
	struct v4l2_ctrl_handler *handler = &info->handler;
	struct v4l2_ctrl *ctrl;
	int i;
	int ret = 0;

	v4l2_ctrl_handler_init(handler, 2 + ARRAY_SIZE(sensor_custom_ctrls));

	v4l2_ctrl_new_std(handler, ops, V4L2_CID_GAIN, 1 * 1600, 256 * 1600, 1,
			  1 * 1600);
	ctrl = v4l2_ctrl_new_std(handler, ops, V4L2_CID_EXPOSURE, 0, 65536 * 16,
				 1, 0);
	if (ctrl != NULL)
		ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
	for (i = 0; i < ARRAY_SIZE(sensor_custom_ctrls); i++)
		v4l2_ctrl_new_custom(handler, &sensor_custom_ctrls[i], NULL);

	if (handler->error) {
		ret = handler->error;
		v4l2_ctrl_handler_free(handler);
	}

	sd->ctrl_handler = handler;

	return ret;
}

static ssize_t mode_set(struct device *dev, struct device_attribute *attr,
			const char *buf, size_t count)
{
	if (buf[0] == '0') {
		irs2975c_is_master = 0;
		sensor_print("set slave mode\n");
	} else {
		irs2975c_is_master = 1;
		sensor_print("set master mode\n");
	}
	return count;
}

static DEVICE_ATTR(mode, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR, NULL, mode_set);

static ssize_t reset_set(struct device *dev, struct device_attribute *attr,
			 const char *buf, size_t count)
{
	vin_gpio_set_status(sd_g, RESET, 1);
	vin_gpio_write(sd_g, RESET, CSI_GPIO_LOW);
	usleep_range(10000, 12000);
	vin_gpio_write(sd_g, RESET, CSI_GPIO_HIGH);
	sensor_print("reset sensor.\n");
	return count;
}

static DEVICE_ATTR(reset, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR, NULL,
		   reset_set);

static struct attribute *deptrum_phantom_attributes[] = { &dev_attr_reset.attr,
							  &dev_attr_mode.attr,
							  NULL };

static const struct attribute_group deptrum_phantom_attr_group = {
	.attrs = deptrum_phantom_attributes,
};

static int sensor_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
{
	struct v4l2_subdev *sd;
	struct sensor_info *info;
	int ret;

	sensor_print("deptrum nebula probe start!v%s\n", NEBULA_VERSION);

	info = kzalloc(sizeof(*info), GFP_KERNEL);
	if (info == NULL)
		return -ENOMEM;
	sd = &info->sd;
	cci_dev_probe_helper(sd, client, &sensor_ops, &cci_drv);
	sensor_init_controls(sd, &sensor_ctrl_ops);
	mutex_init(&info->lock);
#ifdef CONFIG_SAME_I2C
	info->sensor_i2c_addr = I2C_ADDR >> 1;
#endif
	info->fmt = &sensor_formats[0];
	info->fmt_pt = &sensor_formats[0];
	info->win_pt = &sensor_win_sizes[0];
	info->fmt_num = N_FMTS;
	info->win_size_num = N_WIN_SIZES;
	info->sensor_field = V4L2_FIELD_NONE;
	info->af_first_flag = 1;

	ret = sysfs_create_group(&cci_drv.cci_device.kobj,
				 &deptrum_phantom_attr_group);
	if (ret != 0) {
		sensor_err("sysfs_create_group error\n");
		return -ENODEV;
	}

	calib_data = vmalloc(CALIB_INFO_MAX_LEN);
	if (calib_data == NULL)
		return -ENOMEM;
	sd_g = sd;

	return 0;
}
static int sensor_remove(struct i2c_client *client)
{
	struct v4l2_subdev *sd;

	sd = cci_dev_remove_helper(client, &cci_drv);
	kfree(to_state(sd));
	if (calib_data) {
		vfree(calib_data);
		calib_data = NULL;
	}
	return 0;
}

static const struct i2c_device_id sensor_id[] = { { SENSOR_NAME, 0 }, {} };

MODULE_DEVICE_TABLE(i2c, sensor_id);

static struct i2c_driver sensor_driver = {
    .driver =
        {
            .owner = THIS_MODULE,
            .name = SENSOR_NAME,
        },
    .probe = sensor_probe,
    .remove = sensor_remove,
    .id_table = sensor_id,
};
static __init int init_sensor(void)
{
	return cci_dev_init_helper(&sensor_driver);
}

static __exit void exit_sensor(void)
{
	cci_dev_exit_helper(&sensor_driver);
}

module_init(init_sensor);
module_exit(exit_sensor);
